package cn.keniykey.mc.viewlibrary.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.logging.Logger;

import cn.keniykey.mc.viewlibrary.ViewLibraryMain;

/**
 * 反射Class
 */
public class ReflectionClass {
	private final Class<?> clazz;

	public ReflectionClass(final Class<?> clazz) {
		this.clazz = clazz;
	}

	public Class<?> getClazz() {
		return this.clazz;
	}

	public boolean isInstance(final Object object) {
		return this.clazz.isInstance(object);
	}

	private static Class<?>[] coverClasses(final Object[] objs) {
		final Class<?>[] classes = new Class[objs.length];
		for (int index = 0; index < objs.length; index++) {
			final Object obj = objs[index];
			if (obj instanceof Class) {
				classes[index] = (Class<?>) obj;
				continue;
			}
			if (obj instanceof ReflectionClass) {
				classes[index] = ((ReflectionClass) obj).clazz;
				continue;
			}
			if (obj instanceof String) {
				classes[index] = ReflectionUtil.findClass((String) obj);
				continue;
			}
			classes[index] = obj.getClass();
		}
		return classes;
	}
	/**
	 * 仅识别非泛类方法参数，泛型请使用SearchReflectionMethod
	 * 执行逻辑，依次遍历类方法，符合给定参数的方法
	 */
	public ReflectionMethod getMethod(final String name, final Object... anythings) {
		final Class<?>[] classes = coverClasses(anythings);
		try {
			return new ReflectionMethod(this.clazz.getMethod(name, classes));
		} catch (NoSuchMethodException ex) {
		}
		try {
			return new ReflectionMethod(this.clazz.getDeclaredMethod(name, classes));
		} catch (NoSuchMethodException ex) {
		}
		final StringBuilder builder = new StringBuilder(
				"can not get the method(NoSuchMethodException)(获取不到指定Method方法): ");
		builder.append(name).append(": ");
		for (final Class<?> clazz : classes) {
			builder.append(clazz.getName()).append(", ");
		}
		throw new RuntimeException(builder.substring(0, builder.length() - 2));
	}
	/**
	 * 仅识别非泛类方法参数，泛型请使用SearchReflectionMethod
	 * 执行逻辑，依次遍历类方法，符合给定参数的方法
	 */
	public ReflectionMethod findMethodByParameters(final Object... anythings) {
		final Class<?>[] classes = coverClasses(anythings);
		final HashSet<Method> methods = new HashSet<>();
		Collections.addAll(methods, this.clazz.getMethods());
		Collections.addAll(methods, this.clazz.getDeclaredMethods());
		try {
			formethod: for (final Method method : methods) {
				final Class<?>[] method_classes = method.getParameterTypes();
				if (method_classes.length != classes.length) continue;
				for (int index = 0; index < classes.length; index++) {
					if (!classes[index].equals(method_classes[index]))
						continue formethod;
				}
				return new ReflectionMethod(method);
			}
			final StringBuilder builder = new StringBuilder("can not find the Method(NoSuchMethodException)(找不到符合的Method方法): ");
			for (final Class<?> clazz : classes) {
				builder.append(clazz.getName()).append(", ");
			}
			throw new RuntimeException(builder.substring(0, builder.length() - 2));
		} finally {
			methods.clear();
		}
	}

	public ReflectionMethod findMethod(final SearchReflectionMethod... searchs) {
		for(final SearchReflectionMethod search : searchs) {
			try {
				return new ReflectionMethod(search.findMethod(this.clazz));
			}catch(Exception ex) {}
		}
		throw new RuntimeException(this.clazz.getName()
				+ ": can not find the Method(NoSuchMethodException)(找不到符合的Method方法): " + Arrays.toString(searchs));
	}
	public ArrayList<ReflectionMethod> findMethods(SearchReflectionMethod... searchs) {
		if (searchs.length == 0) throw new RuntimeException("method parameters cannot be empty(方法参数不能为空白)");
		final LinkedList<ReflectionMethod> list = new LinkedList<>();
		for(final SearchReflectionMethod search : searchs) {
			try {
				for(final Method constructor : search.findMethods(this.clazz)) list.add(new ReflectionMethod(constructor));
			}catch(Exception ex) {}
		}
		try {
			return new ArrayList<>(list);
		}finally {
			list.clear();
		}
	}

	public ReflectionMethod findMethodByName(final String... names) {
		final HashSet<Method> methods = new HashSet<>();
		Collections.addAll(methods, this.clazz.getMethods());
		Collections.addAll(methods, this.clazz.getDeclaredMethods());
		try {
			for (final Method method : methods) {
				for (final String name : names) {
					if (method.getName().equals(name)) return new ReflectionMethod(method);
				}
			}
			final StringBuilder builder = new StringBuilder(
					"can not find the Method(NoSuchMethodException)(找不到符合的Method方法): ");
			for (final String name : names) {
				builder.append(name).append(", ");
			}
			throw new RuntimeException(builder.substring(0, builder.length() - 2));
		} finally {
			methods.clear();
		}
	}
	/**
	 * 仅识别非泛类Method返回，泛型请使用SearchReflectionMethod
	 * 执行逻辑，依次遍历类方法，符合给定参数的方法
	 * 请使用Void.Type，不要使用Null
	 */
	public ReflectionMethod findMethodByReturnType(final ReflectionClass... reclasses) {
		final Class<?>[] classes = new Class<?>[reclasses.length];
		for (int index = 0; index < reclasses.length; index++) {
			final ReflectionClass reclass = reclasses[index];
			classes[index] = reclass == null ? Void.TYPE : reclass.clazz;
		}
		return findMethodByReturnType(classes);
	}

	/**
	 * 仅识别非泛类Method返回，泛型请使用SearchReflectionMethod
	 * 执行逻辑，依次遍历类方法，符合给定参数的方法
	 * 请使用Void.Type，不要使用Null
	 */
	public ReflectionMethod findMethodByReturnType(final Class<?>... classes) {
		if (classes.length == 0) throw new RuntimeException("method parameters cannot be empty(方法参数不能为空白)");
		final HashSet<Method> methods = new HashSet<>();
		Collections.addAll(methods, this.clazz.getMethods());
		Collections.addAll(methods, this.clazz.getDeclaredMethods());
		try {
			for(final Method method : methods) {
				final Class<?> method_clazz = method.getReturnType();
				for(final Class<?> clazz : classes) {
					if(clazz.equals(method_clazz)) return new ReflectionMethod(method);
				}
			}
			final StringBuilder builder = new StringBuilder("can not find the Method(NoSuchMethodException)(找不到符合的Method方法): ");
			for (final Class<?> clazz : classes) {
				builder.append(clazz.getName()).append(", ");
			}
			throw new RuntimeException(builder.substring(0, builder.length() - 2));
		} finally {
			methods.clear();
		}
	}
	public ReflectionConstructor findConstructor(SearchReflectionConstructor... searchs) {
		for(final SearchReflectionConstructor search : searchs) {
			try {
				return new ReflectionConstructor(search.findConstructor(this.clazz));
			}catch(Exception ex) {}
		}
		throw new RuntimeException(this.clazz.getName()
				+ ": cannot find the constructor(NoSuchConstructorException)(找不到指定Constructor): " + Arrays.toString(searchs));
	}
	/**
	 * 仅识别非泛型Class
	 */
	public ReflectionConstructor getConstructor(final Object... anythings) {
		final Class<?>[] classes = coverClasses(anythings);
		try {
			return new ReflectionConstructor(this.clazz.getConstructor(classes));
		} catch (NoSuchMethodException ex) {
		}
		try {
			return new ReflectionConstructor(this.clazz.getDeclaredConstructor(classes));
		} catch (NoSuchMethodException ex) {
		}
		final StringBuilder builder = new StringBuilder("can not get the constructor(NoSuchMethodException)(获取不到指定Constructor方法): ");
		for (final Class<?> clazz : classes) {
			builder.append(clazz.getName()).append(", ");
		}
		throw new RuntimeException(builder.substring(0, builder.length() - 2));
	}
	public ReflectionConstructor findConstructor(final int parameter_amount) {
		final HashSet<Constructor<?>> constructors = new HashSet<>();
		Collections.addAll(constructors, this.clazz.getConstructors());
		Collections.addAll(constructors, this.clazz.getDeclaredConstructors());
		try {
			for (final Constructor<?> con : constructors) {
				if (con.getParameterCount() == parameter_amount) return new ReflectionConstructor(con);
			}
		}finally {
			constructors.clear();
		}
		throw new RuntimeException("can not find the constructor(找不到指定Constructor): " + parameter_amount);
	}
	public ArrayList<ReflectionConstructor> findConstructors(SearchReflectionConstructor... searchs) {
		if (searchs.length == 0) throw new RuntimeException("method parameters cannot be empty(方法参数不能为空白)");
		final LinkedList<ReflectionConstructor> list = new LinkedList<>();
		for(final SearchReflectionConstructor search : searchs) {
			try {
				for(final Constructor<?> constructor : search.findConstructors(this.clazz)) list.add(new ReflectionConstructor(constructor));
			}catch(Exception ex) {}
		}
		try {
			return new ArrayList<>(list);
		}finally {
			list.clear();
		}
	}
	public ReflectionField findField(SearchReflectionField... searchs) {
		for(final SearchReflectionField search : searchs) {
			try {
				return new ReflectionField(search.findField(this.clazz));
			}catch(Exception ex) {}
		}
		throw new RuntimeException(this.clazz.getName()
				+ ": cannot find the field(NoSuchFieldException)(找不到指定Field参数): " + Arrays.toString(searchs));
	}
	/**
	 * @param names 欲要反射参数可能的名字
	 */
	public ReflectionField findFieldByName(final String... field_names) {
		for (final String name : field_names) {
			try {
				return new ReflectionField(this.clazz.getField(name));
			} catch (NoSuchFieldException ex) {
			}
			try {
				return new ReflectionField(this.clazz.getDeclaredField(name));
			} catch (NoSuchFieldException ex) {
			}
		}
		final StringBuilder builder = new StringBuilder("can not find the field(NoSuchFieldException)(找不到指定Field参数): ");
		for (final String fieldname : field_names) {
			builder.append(fieldname).append(", ");
		}
		throw new RuntimeException(builder.substring(0, builder.length() - 2));
	}
	/**
	 * 仅识别单类型Field，泛型请使用SearchReflectionField
	 * 执行逻辑，依次遍历类参数，符合给定参数的Field
	 */
	public ReflectionField findField(final ReflectionClass... classes) {
		if (classes.length == 0) throw new RuntimeException("method parameters cannot be empty(方法参数不能为空白)");
		final Class<?>[] clazzs = new Class[classes.length];
		for (int index = 0; index < classes.length; index++) clazzs[index] = classes[index].clazz;
		return this.findField(clazzs);
	}

	/**
	 * 仅识别单类型Field，泛型请使用SearchReflectionField
	 * 执行逻辑，依次遍历类参数，符合给定参数的Field
	 */
	public ReflectionField findField(final Class<?>... classes) {
		if (classes.length == 0) throw new RuntimeException("method parameters cannot be empty(方法参数不能为空白)");
		final HashSet<Field> fields = new HashSet<>();
		Collections.addAll(fields, this.clazz.getFields());
		Collections.addAll(fields, this.clazz.getDeclaredFields());
		try {
			for (final Field field : fields) {
				final Class<?> field_class = field.getType();
				for(final Class<?> clazz : classes) {
					if(clazz.equals(field_class)) return new ReflectionField(field);
				}
			}
			final StringBuilder builder = new StringBuilder("can not find the field(NoSuchFieldException)(找不到指定Field参数): ");
			for (final Class<?> clazz : classes) {
				builder.append(clazz.getName()).append(", ");
			}
			throw new RuntimeException(builder.substring(0, builder.length() - 2));
		} finally {
			fields.clear();
		}
	}
	public ArrayList<ReflectionField> findFields(SearchReflectionField... searchs) {
		if (searchs.length == 0) throw new RuntimeException("method parameters cannot be empty(方法参数不能为空白)");
		final LinkedList<ReflectionField> list = new LinkedList<>();
		for(final SearchReflectionField search : searchs) {
			try {
				for(final Field field : search.findFields(this.clazz)) list.add(new ReflectionField(field));
			}catch(Exception ex) {}
		}
		try {
			return new ArrayList<>(list);
		}finally {
			list.clear();
		}
	}
	/**
	 * 仅识别单类型Field，泛型请使用SearchReflectionField
	 * 执行逻辑，依次遍历类参数，符合给定参数的Field
	 */
	public ArrayList<ReflectionField> findFields(final Class<?>... classes) {
		if (classes.length == 0) throw new RuntimeException("method parameters cannot be empty(方法参数不能为空白)");
		final HashSet<Field> fields = new HashSet<>();
		Collections.addAll(fields, this.clazz.getFields());
		Collections.addAll(fields, this.clazz.getDeclaredFields());
		final LinkedList<ReflectionField> turnfields = new LinkedList<>();
		try {
			for (final Field field : fields) {
				final Class<?> field_class = field.getType();
				for(final Class<?> clazz : classes) {
					if(clazz.equals(field_class)) turnfields.add(new ReflectionField(field));
				}
			}
			return new ArrayList<>(turnfields);
		} finally {
			fields.clear();
			turnfields.clear();
		}
	}
	/**
	 * 仅识别单类型Field，泛型请使用SearchReflectionField
	 * 执行逻辑，依次遍历类参数，符合给定参数的Field
	 */
	public ArrayList<ReflectionField> findFields(final ReflectionClass... classes) {
		if (classes.length == 0) throw new RuntimeException("method parameters cannot be empty(方法参数不能为空白)");
		final Class<?>[] clazzs = new Class[classes.length];
		for (int index = 0; index < classes.length; index++) clazzs[index] = classes[index].clazz;
		return this.findFields(clazzs);
	}
	public void showMethodsLogger() {
		final Logger logger = ViewLibraryMain.getPlugin().getLogger();
		logger.warning("---------------" + this.clazz.getName() + "--------------------");
		final HashSet<Method> methods = new HashSet<>();
		Collections.addAll(methods, this.clazz.getMethods());
		Collections.addAll(methods, this.clazz.getDeclaredMethods());
		for(final Method method : methods) {
			logger.warning("method_name: " + method.getName());
			int index = 0;
			final Type[] parametertypes = method.getGenericParameterTypes();
			for(Type par_type : parametertypes) {
				final StringBuilder strb = new StringBuilder("method_par_");
				strb.append(++index).append(": ");
				final Object obj_par = ReflectionGenericClass.getParameterClasses(par_type);
				if(obj_par instanceof Class) {
					strb.append("[Class]");
					final Class<?> clazz_par = (Class<?>)obj_par;
					strb.append(clazz_par.getName());
				}else if(obj_par instanceof LinkedList) {
					strb.append("[LinkedList]");
					@SuppressWarnings("unchecked")
					final LinkedList<Class<?>> linke_clazz_par = (LinkedList<Class<?>>) obj_par;
					strb.append("<C>");
					strb.append(linke_clazz_par.removeFirst().getName());
					for(Class<?> linked_clazz : linke_clazz_par) {
						strb.append(", [G]").append(linked_clazz.getName());
					}
				}
				logger.warning(strb.toString());
			}
		}
		logger.warning("------------------end-------------------------");
	}
}